/**
 * 课后作业 对比js和dart数据类型,找出区别
 * 
 * 
 * 变量声明
 * 
 * 1.var 关键字
 * dart和js都支持var关键字，使用 var 关键词进行声明的时候，dart 会自动推断出 当前变量的类型，如果在变量声明的时候没有进行赋值，那么该类型就是动态的，类似于 TS 的 any。在类型推断上跟 TypeScript 是一致的。
 * JavaScript 是一门弱类型的语言，而 Dart 是强类型的语言
 * 但dart也支持一些弱类型，Dart 中弱类型有var, Object 以及dynamic
 * var, Object，dynamic区别
 * (1) var 初始可定义, 如果有初始值，那么其类型将会被锁定，定义之后不可改变类型
 * (2) Object 动态任意类型，编译阶段检查类型
 * (3) dynamic 动态任意类型，编译阶段不检查类型
 * var 初始化确定类型后不可更改类型， Object 以及dynamic 可以更改类型
 * Object 编译阶段检查类型, 而 dynamic 编译阶段不检查类型
 * 
 * 2.final 关键字 
 * final和const区别 
 * const比final更加严格。final只是要求变量在初始化后值不变，但通过final，我们无法在编译时（运行之前）知道这个变量的值；而const所修饰的是编译时常量，我们在编译时就已经知道了它的值。
 * 
 * 3.默认值
 * js中变量的初始值是undefined
 * 在 Dart 中，未初始化的变量拥有一个默认的初始化值： null。即便数字也是如此，因为在 Dart 中一切皆为对象，数字也不例外。要用final的话必须定义一个初始值
 * 
 * 4.类型判断
 * js用 typeof 来判断基本类型（字符串（string）、数值（number）、布尔值（boolean）、undefined），用 instanceof 来判断引用类型（Object对象Array数组Function函数）
 * dart 用关键字 is 来进行类型判断，返回布尔值
 * 
 * 5.类型转换
 * js类型转换
 * // json和字符串互相转换
    * var obj = {a:'2.2'}
    * var str = JSON.stringify(obj) // "{"a":"2.2"}"
    * JSON.parse(str) // {a: "2.2"}
    * Number(obj.a) // 2.2 // 转成number类型
    * parseInt(obj.a) // 2 转成int类型
 * Dart通过Dart:convert中内置的内置的JSON解码器json.decode()进行转换
 * 
 * 6.布尔值
 * 在js中，自动类型转换，使用判断的时候空字符串，0，null，undefined都会被转换为false
 * Dart是强类型语言，不会进行自动类型转换
 * 
 * 7.字符串
 * js
 * var str = 'string' // 单引号
  var str2 = "string2" // 双引号
  var str3 = 'test ' + "string" // 字符串拼接
  var str4 = `string3${str2}` // 反引号-变量字符串

  str.length // 6 字符串长度
  str.charAt(1) // s 返回给定位置的字符
  str.charcodeAt(1) // 返回给定位置字符的字符编码
  str[1] //s ie8+

  str.concat('a') //stringa 可以接受任意多个参数拼接成新的字符串，但不会改变原字符串
  str.slice(0,3) //str 截取字符串
  str.substring(3) //ing 截取字符串
  str.substr(0,1) //s 截取字符串
  str.indexOf('s') // 0 可接受两个参数，找到返回位置，找不到返回-1
  str.lastIndexOf('t') // 1 从数组的末尾开始查找
  str.trim() //删除前置和后缀的空格 返回的是字符串的副本，原始字符串不变

  str.toLowerCase() //转小写
  str.toUpperCase() //转大写
  str.toLocaleLowerCase() //string 转小写，针对地区的方法
  str.toLocaleUpperCase() //STRING 转大写，针对地区的方法

  str.match('s') // ["s", index: 0, input: "string", groups: undefined]
  str.search('s') //0 接受一个正则，返回字符串中第一个匹配项的索引，没有返回-1
  str.replace('s','c') //ctring 替换字符串,可正则匹配
  str.split() //["string"] 分割字符串，并返回一个数组。


  dart
  String a = 'string' // 单引号 
  String b = "string" // 双引号 
  // 多行字符串
  String c = '''string 
  huanhang'''
  // 使用前缀 r 创建 raw string，字符串内不会进行转义
  String d = r'haha \n breakLine' // 不换行，输出haha \n breakLine
  // 使用变量$name或${name}都可以，前一种方法的后面不能直接跟字符串，要用空格或者逗号等方式隔开
  String name = 'hello';
  assert('$name string'); // hello string
  assert('${name} string'); // hello string
  assert(name.length); // 6 字符串长度
  assert(name.isEmpty) // false 判断是否为空
  assert(name.isNotEmpty) // true 是否不为空
  assert(name.substring(0, 2)) // he 字符串切割
  assert(name.substring(3)) // lo 从指定index至末尾
  String e = "a,b,,"; 
  List<String> a6 = e.split(",");// 使用，分割，返回的是一个数组,同js [a,b, , ]
  // 查找并替换 相当于split 和 join
  String f = "a b,c";
  String g = f.splitMapJoin(",",//查询“,”
    onMatch: (Match match) { // 用匹配的值替换
      return "a";
    }, onNonMatch: (String nonMatch) { // 用不匹配的值替换
      return "b";
    });
  assert(g);//bab    a b,c  =>   bab
  // 字符串判断
  String = 'aabbbcccc';
  assert(h.startsWith("aa")); //true startsWith以某某开始
  assert(h.startsWith("aa", 3)); //false 从index=3开始判断
  assert(h.endsWith("c")); //true endsWith 以xx结尾
  assert(h.contains("ab")); //true contains是否包含
  assert(h.contains("ac")); //false
  assert(h.contains("ab", 3)); //false 从index=3开始判断
  // 字符串替换
  String i = "stringing";
  assert(i.replaceAll("st","cc"));// ccringing 替换全部符合条件的
  assert(i.replaceFirst("ing", "ss"));//strssing 只替换第一个符合条件的
  assert(i.replaceFirst("ing", "dd",5));//stringdd 从index=5开始 替换第一个符合条件的
  assert(i.replaceRange(0, 3, "z"));// zinging 范围替换 从0-3 含0不含3
  assert(i.replaceAllMapped("i", (Match match){//stryngyng 用方法返回值替换指定的字符串
    return "y";
  }));
  assert(i.replaceFirstMapped("i", (Match match){
    return "333";
  },5)); //string333ng 从index=5开始 用方法返回值替换指定的字符串
  // 字符串查找
  Sting j = 'hello'
  assert(j.indexOf('l')); // 2 从前往后找 返回第一个符合条件的index
  assert(j.lastIndexOf('l')); // 3 从后往前找 返回第一个符合条件的index
  // 转换为大小写
  Stinrg k = 'aaBBcC'
  assert(k.toLowerCase()); // aabbcc
  assert(k.toUpperCase()); // AABBCC  
  // 去除空格
  String l = " aab bcc ";
  assert(l.trim()); //aabbcc 去除左右空格
  assert(l.trimLeft()); //aabbcc 去除左边空格
  assert(l.trimRight()); // aabbcc去除右边空格
  // 补齐长度 剩余位使用指定字符串替换
  String j = "111";
  assert(j.padLeft(6));// 111 剩余3个位 默认使用""补齐
  assert(j.padRight(6,"c")); //111ccc 剩余3个位 指定使用"c"
  assert(j.padRight(6,"dd")); //111dddddd 剩余3个位 每个位指定使用"dd" 替换后总长度不是6
  assert(j.padLeft(2,"e"));//111 如果指定长度小于原字符串长度 返回原字符串

  8.数组
  js

  var list = [1, 2, 3, 4, 5];
  var list1 = [1, 2, 3];
  var list2 = [4, 5];

  console.log(list.length) // 3
  list1.concat(list2) // [1, 2, 3, 4, 5] 连接两个或更多的数组，并返回结果。
  list.every(i=>i>3) // false 检测数值元素的每个元素是否都符合条件。
  list.some(i=>i>3) // true 检测数值元素是否有符合条件的值
  list.filter(i=>i>3)    // [4, 5] 检测数值元素，并返回符合条件所有元素的数组。
  list.find(i=>i=3) // 1 返回符合传入测试（函数）条件的数组元素。
  list.forEach() // 遍历数组
  list.join('') // 12345 把数组的所有元素放入一个字符串。
  list.map(i=>i+1) // [2, 3, 4, 5, 6] 通过指定函数处理数组的每个元素，并返回处理后的数组。
  list.pop() // 5 删除数组的最后一个元素并返回删除的元素。
  list.push(8) // 5 向数组的末尾添加一个或更多元素，并返回新的长度。
  list.shift() // 1 删除并返回数组的第一个元素。
  list.sort() // 排序
  list.toString() // 1,2,3,4,5 把数组转换为字符串，并返回结果。
  list.unshift(8) // [8, 1, 2, 3, 4, 5, 6] 向数组的开头添加一个或更多元素，并返回新的长度。
  list.reduce((curr, next) => curr + next); // 15 数组相加的总和

  dart
  var list = [1, 2, 3];
  assert(list.length == 3);
  assert(list[1] == 2);

  list[1] = 1;
  assert(list[1] == 1);

  // 同js
  list.forEach((i) => print(i)); // 遍历数组
  list.map(i=>i+1) // [2, 3, 4]
  list.sort((num1, num2) => num1 - num2); // 排序
  list.every(i=>i<5) // true 用法同上
  list.reduce((curr, next) => curr + next); // 15 数组相加的总和

  list.fold(2,(curr, next) => curr + next);// 17 用法同reduce，有一个初始值
  list.contains(5) // false 用于判断数组是否包含某个元素
  list.where((i) => i > 2); // [3] 返回数组中满足给定条件的元素集合
  // firstWhere() 返回数组中满足给定条件的第一个元素
  list.firstWhere((i) => i > 2, orElse: () => null); // 3
  // singleWhere() 返回数组中满足给定条件的唯一一个元素，若有多个元素满足条件会抛出异常
  list.singleWhere((i) => i < 2, orElse: () => null);
  List arr = [1, 3, 5, 2, 7, 9];
  arr.take(3).toList() // [1, 3, 5] take(n) 从数组里取 n 个元素
  arr.skip(4).toList() // [7, 9] skip(n) 跳过数组中的 n 个元素
  arr.take(3).skip(2).take(1).toList() // [5]
  var clonedArr = List.from(list); // [1, 2, 3] from 克隆一个数组
  print(clonedArr);
  var arr1 = [[2, 5], [7], [11, 12]];
  arr1.expand((item) => item).toList(); // [2, 5, 7, 11, 12]
  list.expand((item) => [item * 8]).toList();// [8, 16, 24]
  // 当对每一项进行计算时类似于 map() [8, 16, 24]
  list.map((item) => item * 8).toList();
  list.add(10); // [1,2,3,10] 向数组中添加元素
  list.addAll([15, 21]); // [1,2,3,15,21] 向数组中添加另一个数组的所有元素

  
 */